// TelnetOption.cpp: implementation of the CTelnetOption class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "AnsiTerminal.h"
#include "TelnetOption.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTelnetOption::CTelnetOption(ITelnetDataSender *pTelnetDataSender, char optionType, CTelnetOptionEvents *pEvents) : OPTION_TYPE(optionType)
{
	m_pTelnetDataSender = pTelnetDataSender;
	m_pEvents = pEvents;

	us = NO;
	usq = EMPTY;
	him = NO;
	himq = EMPTY;
}

CTelnetOption::~CTelnetOption()
{

}

void CTelnetOption::OnDo()
{
	switch(us)
	{
	case NO:
		if(checkAgreeUsOn())
		{
			us = YES;
			sendWill();
			OnUsChange();
		}
		else
		{
			sendWont();
		}
		break;
	case YES:
		// ignore
		break;
	case WANTNO:
		if(usq == EMPTY)
		{
			us = NO;
			OnUsChange();
		}
		else
		{
			us = YES;
			OnUsChange();
			usq = EMPTY;
		}
		break;
	case WANTYES:
		if(usq == EMPTY)
		{
			us = YES;
			OnUsChange();
		}
		else
		{
			us = WANTNO;
			usq = EMPTY;
			sendWont();
		}
	}
}

void CTelnetOption::OnDont()
{
	switch(us)
	{
	case NO:
		// ignore
		break;
	case YES:
		us = NO;
		sendWont();
		OnUsChange();
		break;
	case WANTNO:
		if(usq == EMPTY)
		{
			us = NO;
			OnUsChange();
		}
		else
		{
			us = WANTYES;
			usq = EMPTY;
			sendWill();
		}
		break;
	case WANTYES:
		if(usq == EMPTY)
		{
			us = NO;
			OnUsChange();
		}
		else
		{
			us = NO;
			OnUsChange();
			usq = EMPTY;
		}
	}
}

void CTelnetOption::OnWill()
{
	switch(him)
	{
	case NO:
		if(checkAgreeHimOn())
		{
			him = YES;
			OnHimChange();
			sendDo();
		}
		else
		{
			sendDont();
		}
		break;
	case YES:
		// ignore
		break;
	case WANTNO:
		if(himq == EMPTY)
		{
			him = NO;
			OnHimChange();
		}
		else
		{
			him = YES;
			OnHimChange();
			himq = EMPTY;
		}
		break;
	case WANTYES:
		if(himq == EMPTY)
		{
			him = YES;
			OnHimChange();
		}
		else
		{
			him = WANTNO;
			himq = EMPTY;
			sendDont();
		}
		break;
	}
}

void CTelnetOption::OnWont()
{
	switch(him)
	{
	case NO:
		// ignore
		break;
	case YES:
		him = NO;
		OnHimChange();
		sendDont();
		break;
	case WANTNO:
		if(himq == EMPTY)
		{
			him = NO;
			OnHimChange();
		}
		else
		{
			him = WANTYES;
			himq = EMPTY;
			sendDo();
		}
		break;
	case WANTYES:
		if(himq == EMPTY)
		{
			him = NO;
			OnHimChange();
		}
		else
		{
			him = NO;
			OnHimChange();
			himq = EMPTY;
		}
		break;
	}
}

void CTelnetOption::RequestHimOn()
{
	switch(him)
	{
	case NO:
		him = WANTYES;
		sendDo();
		break;
	case YES:
		// error
		break;
	case WANTNO:
		if(himq == EMPTY)
		{
			if(usq == OPPOSITE)
			{
				himq = OPPOSITE;
			}
			else
			{
				// error
			}
		}
		else
		{
			// error
		}
		break;
	case WANTYES:
		if(himq == EMPTY)
		{
			// error
		}
		else
		{
			himq = EMPTY;
		}
		break;
	}
}

void CTelnetOption::RequestHimOff()
{
	switch(him)
	{
	case NO:
		// error
		break;
	case YES:
		him = WANTNO;
		sendDont();
		break;
	case WANTNO:
		if(himq == EMPTY)
		{
			// error
		}
		else
		{
			himq = EMPTY;
		}
		break;
	case WANTYES:
		if(himq == EMPTY)
		{
			if(usq == OPPOSITE)
			{
				himq = OPPOSITE;
			}
			else
			{
				// error
			}
		}
		else
		{
			// error
		}
		break;
	}
}

void CTelnetOption::RequestUsOn()
{
	switch(us)
	{
	case NO:
		us = WANTYES;
		sendWill();
		break;
	case YES:
		// error
		break;
	case WANTNO:
		if(usq == EMPTY)
		{
			if(himq == OPPOSITE)
			{
				usq = OPPOSITE;
			}
			else
			{
				// error
			}
		}
		else
		{
			// error
		}
		break;
	case WANTYES:
		if(usq == EMPTY)
		{
			// error
		}
		else
		{
			usq = EMPTY;
		}
		break;
	}
}

void CTelnetOption::RequestUsOff()
{
	switch(us)
	{
	case NO:
		// error
		break;
	case YES:
		us = WANTNO;
		sendWont();
		break;
	case WANTNO:
		if(usq == EMPTY)
		{
			// error
		}
		else
		{
			usq = EMPTY;
		}
		break;
	case WANTYES:
		if(usq == EMPTY)
		{
			if(himq == OPPOSITE)
			{
				usq = OPPOSITE;
			}
			else
			{
				// error
			}
		}
		else
		{
			// error
		}
		break;
	}
}


void CTelnetOption::RegisterEvents(CTelnetOptionEvents *pEvents)
{
	m_pEvents = pEvents;
}

BOOL CTelnetOption::checkAgreeUsOn()
{
	if(!m_pEvents) return FALSE;
	return m_pEvents->AgreeUsOn(this);
}

BOOL CTelnetOption::checkAgreeHimOn()
{
	if(!m_pEvents) return FALSE;
	return m_pEvents->AgreeHimOn(this);
}

void CTelnetOption::sendOptionCommand(char action)
{
	m_pTelnetDataSender->SendOptionCommand(OPTION_TYPE, action);
// 	OptionBuf[1] = action;
// 	OptionBuf[2] = OPTION_TYPE;
// 	m_pSocketLayer->SendBuf(OptionBuf, 3);
}

void CTelnetOption::sendDo()
{
	sendOptionCommand(DO);
}

void CTelnetOption::sendDont()
{
	sendOptionCommand(DONT);
}

void CTelnetOption::sendWill()
{
	sendOptionCommand(WILL);
}

void CTelnetOption::sendWont()
{
	sendOptionCommand(WONT);
}

void CTelnetOption::OnUsChange()
{
	if(m_pEvents)
	{
		m_pEvents->OnOptionChange(this);
	}
}

void CTelnetOption::OnHimChange()
{
	if(m_pEvents)
	{
		m_pEvents->OnOptionChange(this);
	}
}


BOOL CTelnetOption::IsUsOn()
{
	return us == YES;
}

BOOL CTelnetOption::IsHimOn()
{
	return him == YES;
}

void CTelnetOption::SetParameters(const char* buf, int bufLen)
{
	// do nothing
}
